//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008-2010, Shane J. M. Liesegang
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright 
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright 
//       notice, this list of conditions and the following disclaimer in the 
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the copyright holder nor the names of any 
//       contributors may be used to endorse or promote products derived from 
//       this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "Common.h"
#include "StringUtil.h"

class AIBrainState;
class Sentient;

class AIBrain
{
	typedef hashmap_ns::hash_map<String, AIBrainState*> BrainStateTable;
public:
	AIBrain();
	void SetActor(Sentient* actor) {_actor = actor;}

	virtual ~AIBrain();

	virtual void AddState(const String &id, AIBrainState* state);

	virtual void Update(float dt);
	virtual void GotoState(const String &id);

	Sentient* GetActor() {return _actor;}

	void Render();
	void GotoNullState();

	void EnableDrawing(bool enable);

protected:
	BrainStateTable				_brainStateTable;
	BrainStateTable::iterator	_current;
	Sentient*					_actor;
	bool						_drawMe;
};

class AIEvent;

class AIBrainState
{
	typedef std::vector<AIEvent*> EventList;
public:
	virtual ~AIBrainState();
	virtual void Initialize(AIBrain* brain) {_brain = brain;}
	void Update(float dt);
	virtual void CustomUpdate(float){}
	virtual void BeginState(AIBrainState* /*previousState*/){}
	void EndState(AIBrainState* nextState);
	virtual void CustomEndState(AIBrainState*){}
protected:
	virtual void GotoState(const String &id);
	virtual AIEvent* RegisterEvent(AIEvent* newEvent);
	virtual void UnregisterEvent(AIEvent* oldEvent);
	Sentient* GetActor() {return _brain->GetActor();}
private:
	void ClearEvents();
	void StopEvent(AIEvent* pEvent);
protected:
	AIBrain*		_brain;
	EventList		_eventList;
};

#define DECLARE_AISTATE(cls) \
	typedef cls MyClass;

#define DECLARE_BASESTATE(BaseStateID, StateDataType) \
class BaseStateID : public AIBrainState \
{ \
public: \
	BaseStateID(StateDataType& _StateData) \
	: StateData(_StateData) \
{} \
protected: \
	StateDataType& StateData; \
};

#define DECLARE_SHAREDDATASTATE( ThisStateID, BaseStateID, StateDataType ) \
        DECLARE_AISTATE(ThisStateID) \
        ThisStateID( StateDataType& _StateData ) \
        : BaseStateID( _StateData ) \
{}


/*abstract*/ class AIEvent
{
public:
        virtual ~AIEvent() {}
        virtual void Stop() {}
        virtual void Update(float /*dt*/) {}

        void SetBrain( AIBrain* pBrain ) {_brain = pBrain;}

protected:
        AIBrain* GetBrain() {return _brain;}
        Sentient* GetActor() {return _brain->GetActor();}
        virtual void IssueCallback() {}
private:
        AIBrain*        _brain;
};

#define REGISTER_AIEVENT( ev, cb, params ) \
        ((ev##Template<MyClass>*)this->RegisterEvent( new ev##Template<MyClass>(this, &MyClass::cb) ))->Initialize params

#define UNREGISTER_AIEVENT(oldEvent) \
        UnregisterEvent(oldEvent)
        

#define DECLARE_AIEVENT_BASE( FromClass ) \
template<class T> \
class FromClass##Template : public FromClass \
{ \
public: \
        typedef void(T::*AIBrainStateCallback)( FromClass* newEvent ); \
        FromClass##Template( T* cbObj, AIBrainStateCallback cb ) \
                : _cbObj(cbObj) \
                , _cb(cb) \
        {} \
protected: \
        virtual void IssueCallback()\
        { \
                (*_cbObj.*_cb)(this); \
        } \
private: \
        T*                                              _cbObj; \
        AIBrainStateCallback    _cb; \
};
